#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <unistd.h>
#include "uart.h"
#include "pwm.h"
#include "adc.h"

int uart_flag;
float adc_data[50000];
unsigned int adc_cont;
pthread_t tidU,tidF,tidV;

/* 注意：当有数据来时，并不是一个字节一个字节的进入处理函数，而是只进入一次 */
/* 信号处理函数,当串口有数据可读时，会跳转到该函数执行 */
static void io_handler(int sig, siginfo_t *info, void *context)
{
    if(SIGRTMIN != sig)
    return;
    /* 判断串口是否有数据可读 */
    if(POLL_IN == info->si_code) {
        read(uart_fd, recive_buf, sizeof(recive_buf));
        recive_flag = 1;
    }
}

/* 异步I/O初始化函数 */
static void async_io_init(void)
{
    struct sigaction sigatn;
    int flag;

    /* 使能异步 I/O */
    flag = fcntl(uart_fd, F_GETFL); //使能串口的异步 I/O 功能
    flag |= O_ASYNC;
    fcntl(uart_fd, F_SETFL, flag);

    /* 设置异步 I/O 的所有者 */
    fcntl(uart_fd, F_SETOWN, getpid());
    /* 指定实时信号 SIGRTMIN 作为异步 I/O 通知信号 */
    fcntl(uart_fd, F_SETSIG, SIGRTMIN);

    /* 为实时信号 SIGRTMIN 注册信号处理函数 */
    sigatn.sa_sigaction = io_handler;       //当串口有数据可读时，会跳转到 io_handler 函数
    sigatn.sa_flags = SA_SIGINFO;
    sigemptyset(&sigatn.sa_mask);
    sigaction(SIGRTMIN, &sigatn, NULL);
}

static void *func_uart(void *arg)
{      
    int ret = -1;
    ret = open_uart();
    if(ret) {
        printf("open_uart fail!\n");
        pthread_exit(0);      
    }
    ret = set_opt(uart_fd, 9600, 8, 'N', 1);
    if(ret) {
        printf("set_opt err!\n");
        pthread_exit(0);  
    }
    async_io_init();
    while(1) {
        sleep(1);
        if(recive_flag == 1) {
            recive_flag = 0;
            printf("recive_buf = %s \n",recive_buf);

            /* LED灯控制 */
            if(!strcmp(recive_buf,"ledup\r\n")) {               //开灯，此时灯的占空比为50%
                uart_flag = 1;
            } else if(!strcmp(recive_buf,"leddown\r\n")) {      //关灯，此时关闭PWM
                uart_flag = 2;
            } else if(!strcmp(recive_buf,"led100\r\n")) {      //把灯调亮，此时占空比为100%
                uart_flag = 3;
            }

            /* 舵机控制 */
            else if(!strcmp(recive_buf,"tuo1\r\n")) {           //把床调为1档
                uart_flag = 4;
            } else if(!strcmp(recive_buf,"tuo2\r\n")) {         //把床调为2档
                uart_flag = 5;
            } else if(!strcmp(recive_buf,"tuo3\r\n")) {         //把床调为3档
                uart_flag = 6;
            } else if(!strcmp(recive_buf,"tuo4\r\n")) {         //把床调为4档
                uart_flag = 7;
            }
     
            /* 采集控制 */
            else if(!strcmp(recive_buf,"adcstart\r\n")) {        //开始手术
                uart_flag = 8;
            } else if(!strcmp(recive_buf,"adcstop\r\n")) {      //停止手术
                uart_flag = 9;
            }
            memset(recive_buf, 0, sizeof(recive_buf));
        }
    }
    close(uart_fd);
    pthread_exit(0);
}

static void *func_adc(void *arg)
{   
    int ret = -1;
    while(1) {
        ret = adc_read(&myadc);
        if(!ret) {
            adc_data[adc_cont] = myadc.act;
            printf("adc_data[%d] = %.3f \n",adc_cont, adc_data[adc_cont]);
            adc_cont++;
            if(adc_cont == 2000)
                beng_control(8, 500000);
            else if(adc_cont == 5000) 
                beng_control(8, 666666);
            else if(adc_cont == 6500) 
                beng_control(8, 1000000);     
            if(adc_cont > 6501)
                adc_cont = 0;
        }
        usleep(1000);
    }
    pthread_exit(0);
}

static void *func_pwm(void *arg)
{
    int ret = -1;
    while(1) {  
        if(uart_flag != 0) {
            if(uart_flag < 4) {             //led控制
                led_control(uart_flag);
            } else if(uart_flag < 8) {     //舵机控制
                tuo_control(uart_flag);
            } else if(uart_flag == 8) {     //adc采集和泵
                beng_control(uart_flag, 1000000);
                ret = pthread_create(&tidV, NULL, func_adc, NULL);
                if(ret){
                    fprintf(stderr, "Error:%s\n", strerror(ret));
                    exit(-1);
                }
            } else if(uart_flag == 9) {
                pthread_cancel(tidV);
                pthread_join(tidV,NULL);
                beng_control(uart_flag, 0);
                adc_cont = 0;
            }
        }
        usleep(1000000); 
    }
    pthread_exit(0);
}

int main(int argc, char *argv[])
{   
    int ret = -1;
    ret = pthread_create(&tidU, NULL, func_uart, NULL);
    if(ret){
        fprintf(stderr, "Error:%s\n", strerror(ret));
        exit(-1);
    }

    ret = pthread_create(&tidF, NULL, func_pwm, NULL);
    if(ret){
        fprintf(stderr, "Error:%s\n", strerror(ret));
        exit(-1);
    }

    pthread_join(tidF,NULL);
    pthread_join(tidU,NULL);
}
